package com.springMVC.context;

import com.springMVC.annotation.AutoWired;
import com.springMVC.annotation.Controller;
import com.springMVC.annotation.Service;
import com.springMVC.xml.XmlPaser;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ：candy
 * @date ：Created in 2020/12/1 13:49
 * @description：
 * @version: 1.0
 */
public class WebApplicationContext {

    String contextConfigLocation;

    List<String> calssNameList = new ArrayList<>();

    public Map<String, Object> iocMap = new ConcurrentHashMap<>();

    public WebApplicationContext(String contextConfigLocation) {
        this.contextConfigLocation = contextConfigLocation;
    }

    /**
     * 初始化容器
     */
    public void onRefresh() {

        String packges = XmlPaser.getbasePackage(this.contextConfigLocation.split(":")[1]);

        String[] packs = packges.split(",");

        for (String pack : packs) {
            excuteScanPackage(pack);
        }

        excuteInstance();

        excuteAutoWired();
    }

    private void excuteAutoWired() {
        try {

            for (Map.Entry<String, Object> entry : iocMap.entrySet()) {
                Object bean = entry.getValue();

                Field[] fields = bean.getClass().getDeclaredFields();

                for (Field field : fields) {
                    if (field.isAnnotationPresent(AutoWired.class)) {
                        AutoWired annotation = field.getAnnotation(AutoWired.class);
                        String beanName = annotation.value();

                        field.setAccessible(true);
                        field.set(bean, this.iocMap.get(beanName));
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void excuteInstance() {
        try {

            for (String className : this.calssNameList) {
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Controller.class)) {
                    String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase() + clazz.getSimpleName().substring(1);
                    this.iocMap.put(beanName, clazz.newInstance());
                } else if (clazz.isAnnotationPresent(Service.class)) {
                    Service annotation = clazz.getAnnotation(Service.class);
                    String beanName = annotation.value();
                    this.iocMap.put(beanName, clazz.newInstance());
                }

            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    /**
     * 扫描包
     *
     * @param pack
     */
    private void excuteScanPackage(String pack) {
        URL url = this.getClass().getClassLoader().getResource("/" + pack.replaceAll("\\.", "/"));

        String urlFile = url.getFile();

        File dir = new File(urlFile);

        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                excuteScanPackage(pack + "." + file.getName());
            } else {
                String className = pack + "." + file.getName().replace(".class", "");
                this.calssNameList.add(className);
            }
        }
    }
}
